using System;
using System.Collections;
using Slaks.DocumentSerialization.Document;
using Slaks.DocumentSerialization.TermIdInfo;
using Slaks.Graphs.Comparators;

namespace Slaks.Graphs.GraphBuilder.Extractor
{
    public class ExtractorBuilder : GraphBuilderBase
    {
        /// <summary>
        /// Removes the rest of infrequent vertices leaving at most (numberOfVerticesToLeave)
        /// Used for temporal graph for quering about existing vertices
        /// </summary>
        /// <param name="numberOfVerticesToLeave"></param>
        public void RemoveInfrequentVerticesInTemporalGraph(Graph temporalGraph, int numberOfVerticesToLeave)
        {
            //VertexList vertexList = temporalGraph.GetVertexList();
            //Id2VertexMap id2VertexMapper = temporalGraph.GetId2VertexMap();
            //if (numberOfVerticesToLeave <= 0) return;
            //int totalCount = vertexList.Count;
            //if (numberOfVerticesToLeave >= totalCount) return;
            ////what is desired length of the vertex list

            //temporalGraph.SortVertices(new FrequencyComparer());

            //int currentIndex = numberOfVerticesToLeave;

            //long idToRemove;
            //while (vertexList.Count > numberOfVerticesToLeave)
            //{
            //    idToRemove = vertexList[currentIndex].GetId();
            //    vertexList.RemoveAt(currentIndex);
            //    id2VertexMapper.Remove(idToRemove);
            //}

        }

        /// <summary>
        /// Builds the temporal graph only with vertices
        /// </summary>
        /// <param name="document"></param>
        /// <returns></returns>
        protected Graph BuildTemporalGraph(Document document, BuilderType builderType, int nodesAmount, TermIdInfoMap map)
        {
            Vertex vertex;
            Graph tempGraph = new Graph(document.FileName);
            tempGraph.GraphBuilderType = builderType;
            string fileName = document.OriginalFileName;

            var list = Extractor.Execute(fileName, nodesAmount);
            Hashtable table = document.GenerateString2NodeMap();
            foreach (var phrase in list)
            {
                Node node = table[phrase] as Node;
                if (node == null)
                {
                    if (phrase.Contains(" "))
                    {
                        AddAsSubGraph(tempGraph, phrase, document, map);

                    }

                    //node = Node.CreateNewNode();
                    //node.Term = phrase;
                    //node.TotalTermFrequency = 99;
                    //document.AddNode(node.Id, node);
                    //Console.WriteLine("Found new term: {0}", phrase);
                    //table = document.GenerateString2NodeMap();
                }
                else
                {
                    vertex = tempGraph.CreateAddVertex(node.Id);
                    vertex.Frequency = node.TotalTermFrequency;
                }
            }
            
            return tempGraph;
        }

        private void AddAsSubGraph(Graph graph, string phrase, Document document, TermIdInfoMap map)
        {
            string[] words = phrase.Split(' ');
            Hashtable hash = document.GenerateString2NodeMap();
            Vertex lastVertex = null;
            foreach (var word in words)
            {
                Node node = hash[word] as Node;
                if (node == null)
                {
                    if (map!=null)
                    {
                        node = GetCreateNode(document, word, map);
                    }
                    else
                    {
                        throw new Exception("Unkown term");
                    }
                }
                Vertex current = graph.CreateAddVertex(node.Id);
                if (lastVertex != null)
                {
                    current.AddEdge(lastVertex, "");
                }
                lastVertex = current;
            }
        }

        private Node GetCreateNode(Document document, string word, TermIdInfoMap map)
        {
            Node node = null;
            TermIdInfoElement term = map[word];
            if (term == null)
            {
                term = new TermIdInfoElement(word, map.Count + 1, 1);
                map.Add(word, term);
            }
            
            {
                node = Node.CreateNewNode();
                node.Id = term.Id;
                node.Term = word;
                document.AddNode(node.Id, node);
            }
            return node;
        }


        /// <summary>
        /// Add edges between nodes
        /// </summary>
        /// <param name="document"></param>
        /// <param name="graph">graph to build</param>
        /// <param name="temporalGraph">temporal graph which hold only frequent nodes. it will be queried for them</param>
        /// <param name="currentVertex">the current node</param>
        /// <param name="nParameter">the n-distance parameter</param>
        /// <param name="nDistanceCount">current distance counter</param>
        /// <param name="sentence">current sentence</param>
        /// <param name="sectionType">section type</param>
        protected void AddRelations(Document document,
                                    Graph graph,
                                    Graph temporalGraph,
                                    Vertex currentVertex,
                                    int nParameter,
                                    int nDistanceCount,
                                    Sentence sentence,
                                    Section.SectionType sectionType,
                                    BuilderType builderType
            )
        {
            //if (nDistanceCount > nParameter) return;
            //Node node;
            //long nextId;
            //Vertex nextIdVertex;
            //if (sentence.NextId >= 0)
            //{
            //    //get the nextId.
            //    nextId = sentence.NextId;
            //    //we must check whether the nextId is in the list of frequent nodes.
            //    //if not then we must skip it.

            //    nextIdVertex = temporalGraph.GetVertex(nextId);

            //    node = document.GetNodeById(nextId);
            //    Section section = node.GetSectionByType(sectionType);
            //    if (section == null) return;
            //    Sentence nextSentence = section.GetSentence(sentence.Number, sentence.Place + 1);
            //    if (nextSentence == null) return;

            //    string sectionLabel;

            //    if (nextIdVertex != null) //the nextIdVertex is among frequent nodes
            //    {
            //        if (builderType == BuilderType.NDistanceRepresentationSlaks) sectionLabel = nDistanceCount.ToString();
            //        else if (builderType == BuilderType.NSimpleDistanceRepresentationSlaks) sectionLabel = "Nsimple";
            //        else if (builderType == BuilderType.NormalizedFrequencyRepresentationSlaks) sectionLabel = "normalized";
            //        else if (builderType == BuilderType.RawFrequencyRepresentationSlaks) sectionLabel = "raw";
            //        else if (builderType == BuilderType.SimpleRepresentationSlaks) sectionLabel = "simple";
            //        else if (builderType == BuilderType.StandardRepresentationSlaks) sectionLabel = section.GetSectionTypeString();
            //        else if (builderType == BuilderType.StandardSimpleRepresentationSlaks) sectionLabel = "StandardSimple";
            //        else throw new GraphException("BuilderType is not supported for this kind of relation " + builderType.ToString());

            //        nextIdVertex = graph.CreateAddVertex(nextId);
            //        currentVertex.AddEdge(nextIdVertex, sectionLabel);

            //        AddRelations(document, graph, temporalGraph, currentVertex, nParameter, nDistanceCount + 1, nextSentence, sectionType, builderType);
            //    }
            //    else
            //    {
            //        //the nextIdVertex is not frequent, then we must skip it and find the frequent node.
            //        AddRelations(document, graph, temporalGraph, currentVertex, nParameter, nDistanceCount, nextSentence, sectionType, builderType);
            //    }
            //}
            return;
        }

        /// <summary>
        /// Add edges between nodes
        /// </summary>
        /// <param name="document"></param>
        /// <param name="graph">graph to build</param>
        /// <param name="temporalGraph">temporal graph which hold only frequent nodes. it will be queried for them</param>
        /// <param name="currentVertex">the current node</param>
        /// <param name="nParameter">the n-distance parameter</param>
        /// <param name="nDistanceCount">current distance counter</param>
        /// <param name="sentence">current sentence</param>
        /// <param name="sectionType">section type</param>
        protected void AddRelationsBiderectional(Document document,
                                                 Graph graph,
                                                 Graph temporalGraph,
                                                 Vertex currentVertex,
                                                 int nParameter,
                                                 int nDistanceCount,
                                                 Sentence sentence,
                                                 Section.SectionType sectionType,
                                                 BuilderType builderType
            )
        {
            //if (nDistanceCount > nParameter) return;
            //Node node;
            //long nextId;
            //Vertex nextIdVertex;
            //if (sentence.NextId >= 0)
            //{
            //    //get the nextId.
            //    nextId = sentence.NextId;
            //    //we must check whether the nextId is in the list of frequent nodes.
            //    //if not then we must skip it.

            //    nextIdVertex = temporalGraph.GetVertex(nextId);

            //    node = document.GetNodeById(nextId);
            //    Section section = node.GetSectionByType(sectionType);
            //    if (section == null) return;
            //    Sentence nextSentence = section.GetSentence(sentence.Number, sentence.Place + 1);
            //    if (nextSentence == null) return;

            //    string sectionLabel;

            //    if (nextIdVertex != null) //the nextIdVertex is among frequent nodes
            //    {
            //        if (builderType == BuilderType.NDistanceRepresentationSlaks) sectionLabel = nDistanceCount.ToString();
            //        else if (builderType == BuilderType.NSimpleDistanceRepresentationSlaks) sectionLabel = "no";
            //        else if (builderType == BuilderType.NormalizedFrequencyRepresentationSlaks ||
            //                 builderType == BuilderType.RawFrequencyRepresentationSlaks ||
            //                 builderType == BuilderType.SimpleRepresentationSlaks) sectionLabel = "no";
            //        else sectionLabel = section.GetSectionTypeString();

            //        nextIdVertex = graph.CreateAddVertex(nextId);
            //        currentVertex.AddEdge(nextIdVertex, sectionLabel);
            //        nextIdVertex.AddEdge(currentVertex, sectionLabel);

            //        AddRelationsBiderectional(document, graph, temporalGraph, currentVertex, nParameter, nDistanceCount + 1, nextSentence, sectionType, builderType);
            //    }
            //    else
            //    {
            //        //the nextIdVertex is not frequent, then we must skip it and find the frequent node.
            //        AddRelationsBiderectional(document, graph, temporalGraph, currentVertex, nParameter, nDistanceCount, nextSentence, sectionType, builderType);
            //    }
            //}
            return;
        }
    }}